<template>
	<view class="c-switch-box" @click="switchChange">
		<view class="c-switch__hd" v-if="$slots.default">
			<slot></slot>
		</view>
		<view data-name="switch" class="c-switch-bd" :style="[style_]" :class="[
			checked ? 'c-switch__active' : '',
			disabled_ ? 'c-switch__disabled' : ''
		]">
			<text data-name="text" class="c-switch__text c-switch__text_on" :style="[textStyle_]">{{onText}}</text>
			<text data-name="text" class="c-switch__text c-switch__text_off" :style="[textStyle_]">{{offText}}</text>
			<text data-name="slide" class="c-switch__slide" :style="[slideStyle_]">
				<text class="c-switch__loading spin" v-if="loading" :style="{color: loadingColor}"></text>
			</text>
			<view class="c-switch__mask" v-if="loading && loadingMask_" :style="{backgroundColor: maskBg}"></view>
		</view>
		<view class="c-switch__ft" v-if="$slots.right">
			<slot name="right"></slot>
		</view>
	</view>
</template>

<script>
	export default {
		name: 'c-switch',
		data() {
			return {
				switchWidth: 0,
				translateX: 0,
				checked: false
			}
		},
        watch: {
			value: {
                handler(val) {
                    this.checked = String(val) === 'false' ? false : true;
                },
                immediate: true
            }
        },
		props: {
			value: {//双向绑定的值
				type: [String, Number, Boolean, Array],
				default: false
			},
			onText: {
				type: String,
				default: ''
			},
			offText: {
				type: String,
				default: ''
			},
			textColor: {//滑动球颜色
				type: String,
				default: '#fff'
			},
			textSelColor: {//滑动球颜色
				type: String,
				default: '#fff'
			},
			color: {//开关底座颜色（可以是渐变色）
				type: String,
				default: '#dadada'
			},
			selColor: {//开关底座选中颜色
				type: String,
				default: '#007AFF'
			},
			disabled: {//禁止滑动
				type: [String, Boolean],
				default: false
			},
			disabledText: {//禁止滑动的提示
				type: String,
				default: ''
			},
			slideColor: {//滑动球颜色
				type: String,
				default: '#fff'
			},
			slideSelColor: {//开关开启后滑动球颜色
				type: String,
				default: '#fff'
			},
			scale: {//缩放
				type: [Number, String],
				default: 1
			},
			loading: {//网络请求中
				type: Boolean,
				default: false
			},
			loadingColor: {//loading转圈颜色
				type: String,
				default: '#007AFF'
			},
			mask: {//是否显示蒙层
				type: [String, Boolean],
				default: true
			},
			maskBg: {//蒙层颜色
				type: String,
				default: 'rgba(255, 255, 255, .35)'
			},
			// 标识，选中时触发 <checkbox-group> 的 change 事件，并携带 <checkbox> 的 value值
			label: {
				type: [ String, Number, Boolean ],
				default: 1
			},
		},
		computed: {
			scale_() {
				let scale = this.reservedDecimal(this.scale, 2);
				return scale > 1 ? 1 : scale;
			},
			disabled_() {
				return String(this.disabled) === 'false' ? false : true;
			},
			loadingMask_() {
				return String(this.loadingMask) === 'false' ? false : true;
			},
			textStyle_() {
				let style = {
					color: this.checked ? this.textSelColor : this.textColor
				};
				return style;
			},
			style_() {
				let isGradient = this.color.indexOf('-gradient') !== -1 ? true : false;
				let isSelGradient = this.selColor.indexOf('-gradient') !== -1 ? true : false;
				let color = this.checked ? this.selColor : this.color;
				let bgPro = this.checked ? (isSelGradient ? 'backgroundImage' : 'backgroundColor') : (isGradient ? 'backgroundImage' : 'backgroundColor');
				let style = {
					[bgPro]: color,
					width: this.switchWidth + 'px',
					opacity: this.switchWidth ? 1 : 0,
					transform: this.translateX ? `scale(${this.scale_})` : 'scale(1)'
				}
				return style
			},
			slideStyle_() {
				let isGradient = this.slideColor.indexOf('-gradient') !== -1 ? true : false;
				let isSelGradient = this.slideSelColor.indexOf('-gradient') !== -1 ? true : false;
				let color = this.checked ? this.slideSelColor : this.slideColor;
				let bgPro = this.checked ? (isSelGradient ? 'backgroundImage' : 'backgroundColor') : (isGradient ? 'backgroundImage' : 'backgroundColor');
				let style = {
					[bgPro]: color,
					transform: 'translateX(' + (this.checked ? this.translateX : 0 ) + ')'
				}
				return style
			}
		},
		created() {
			this.parent = this.$getParent('c-switch-group');
			this.parent && this.parent.children.push(this);
		},
		mounted() {
			this.$nextTick(() => {
				// 计算滑块位置,重置rpx转px的偏差问题
				const query = uni.createSelectorQuery().in(this);
				query.selectAll('.c-switch__text, .c-switch__slide, .c-switch').boundingClientRect(data => {
					let switchWidth  = 0;
					let textData = data.filter(o => o.dataset.name === 'text').map(o => {
						let width = o.width
						switchWidth += width;
						return width;
					});
					let switchHeight = (data.find(o => o.dataset.name === 'switch') || {}).height || 0
					let slideData = data.find(o => o.dataset.name === 'slide') || {};
					let maxWidth = Math.max.apply(null, textData);
					let minWidth = Math.min.apply(null, textData);
					let offsetTop = uni.upx2px(20);
					let textDstEqual = (maxWidth - minWidth) < 1;
					let textDst = Math.abs(slideData.width - maxWidth) + (textDstEqual ? 1 : 2) * offsetTop
					this.switchWidth = this.reservedDecimal(switchWidth + textDst);
					let translateX = this.reservedDecimal(this.switchWidth - slideData.width - uni.upx2px(4));
					this.translateX = translateX + 'px';
				}).exec();
			})
		},
		methods: {
			reservedDecimal(num, fixed = 2) {
				if (!num) return Number(0).toFixed(fixed);
				num = String(num);
				let splitNum = num.split('.')
				let firstNum = splitNum[0];
				let lastNum = splitNum[1] ? String(splitNum[1]) : (new Array(fixed + 1)).join('0');
				let toFixedNum = (lastNum && lastNum.length) || 0;
				toFixedNum = toFixedNum > fixed ? fixed : toFixedNum;
				//toFixed会进行四舍五入 所以我们用裁剪
				// return .toFixed(toFixedNum);
				return firstNum + (toFixedNum > 0 ? '.' : '') + lastNum.substr(0, toFixedNum)
			},
			switchChange() {
				if(this.loading) return ;
				if(this.disabled_){
					this.disabledText && this.$toast(this.disabledText)
					return 
				}
                this.emitEvent();
			},
			emitEvent() {
				this.checked = !this.checked;
                this.$emit('change', {
                    detail: {
						value: this.checked
					}
                })
				this.$emit('input', this.checked);
                setTimeout(() => {
                    if (this.parent && this.parent.emitEvent) this.parent.emitEvent();
                }, 50);
			}
		}
	}
</script>

<style lang="scss" scoped>
	.c-switch{
		&__hd{
			padding-right: 10rpx;
		}
		&__ft{
			padding-left: 10rpx;
		}
		&-box{
			display: inline-flex;
			align-items: center;
		}
		&-bd{
			min-width: 96rpx;
			height: 50rpx;
			border-radius: 50rpx;
			display: inline-block;
			vertical-align: middle;
			background-color: #dadada;
			position: relative;
			opacity: 0;
			transition: opacity .2s linear;
			.c-switch__mask{
				position: absolute;
				left: 0;
				top: 0;
				width: 100%;
				height: 100%;
				background-color: rgba(255, 255, 255, .35);
			}
			.c-switch__loading{
				width: 6rpx; 
				height:6rpx;
				position: absolute;
				left: 50%;
				top: 50%;
				transform: translate(-50%, -50%);
				color: #444;
				border-radius: 100%;                      /* 圆角 */
				box-shadow: 14rpx -10rpx 0 .5px currentColor,                /* 右 */    
							0 16rpx currentColor,                  /* 下 */
							-14rpx -10rpx 0 .5px currentColor,                 /* 左 */
							0 -16rpx 0 1px currentColor,        /* 右上, 1.5px扩展 */                    
							14rpx 10rpx currentColor,                 /* 右下 */
							-14rpx 10rpx currentColor;                /* 左下 */
			}
			
			.spin {
				animation: spin 1s steps(8) infinite;
			}
			
			
		}
		&__slide{
			width: 46rpx;
			height: 46rpx;
			background-color: #ffffff;
			border-radius: 100%;
			position: absolute;
			top: 2rpx;
			left: 2rpx;
			transform: translateX(0);
			transition: transform .2s linear;
		}
		&__text{
			position: absolute;
			top: 0;
			line-height: 50rpx;
			height: 50rpx;
			font-size: 26rpx;
			color: #ffffff;
			min-width: 30rpx;
			transition: opacity .2s cubic-bezier(0.4, 0, 0.2, 1);
			&.c-switch__text_on{
				left: 20rpx;
				opacity: 0;
			}
			&.c-switch__text_off{
				right: 20rpx;
				opacity: 1;
			}
		}
		&__active{
			.c-switch__text_on{
				opacity: 1;
			}
			.c-switch__text_off{				
				opacity: 0;
			}
		}
		&__disabled{
			cursor: no-drop;
		}
	}
	@keyframes spin {
		from {transform: rotate(0deg);}
		  to {transform: rotate(360deg);}
	}
</style>
